﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Data;
using System.Text.RegularExpressions;
using System.Data.SqlTypes;

namespace CodeUtils
{
    /// <summary>
    /// Helpers for string manipulation.
    /// </summary>
    public class StringHandlers
    {
        /// <summary>
        /// Left of the first occurance of c
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">Return everything to the left of this character.</param>
        /// <returns>String to the left of c, or the entire string.</returns>
        public static string LeftOf(string src, char c)
        {
            string ret = src;
            int idx = src.IndexOf(c);
            if (idx != -1)
            {
                ret = src.Substring(0, idx);
            }
            return ret;
        }

        /// <summary>
        /// This function will roundoff the value upto 5 digits(i.e. n5) after decimal.
        /// User can change it to n1(for 1 digit) or n2(for 2 digits)etc after decimal.
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static string formatSeparators(string val)
        {
            if (val != string.Empty)
            {
                double dValue = Convert.ToDouble(val);
                return String.Format("{0:n5}", dValue);
                //return val;

            }
            else
                return string.Empty;
        }

        /// <summary>
        /// Left of the n'th occurance of c.
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">Return everything to the left n'th occurance of this character.</param>
        /// <param name="n">The occurance.</param>
        /// <returns>String to the left of c, or the entire string if not found or n is 0.</returns>
        public static string LeftOf(string src, char c, int n)
        {
            string ret = src;
            int idx = -1;
            while (n > 0)
            {
                idx = src.IndexOf(c, idx + 1);
                if (idx == -1)
                {
                    break;
                }
                --n;
            }
            if (idx != -1)
            {
                ret = src.Substring(0, idx);
            }
            return ret;
        }

        /// <summary>
        /// Right of the first occurance of c
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">The search char.</param>
        /// <returns>Returns everything to the right of c, or an empty string if c is not found.</returns>
        public static string RightOf(string src, char c)
        {
            string ret = String.Empty;
            int idx = src.IndexOf(c);
            if (idx != -1)
            {
                ret = src.Substring(idx + 1);
            }
            return ret;
        }
        /// <summary>
        /// Right of the n'th occurance of c
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">The search char.</param>
        /// <param name="n">The occurance.</param>
        /// <returns>Returns everything to the right of c, or an empty string if c is not found.</returns>
        public static string RightOf(string src, char c, int n)
        {
            string ret = String.Empty;
            int idx = -1;
            while (n > 0)
            {
                idx = src.IndexOf(c, idx + 1);
                if (idx == -1)
                {
                    break;
                }
                --n;
            }

            if (idx != -1)
            {
                ret = src.Substring(idx + 1);
            }

            return ret;
        }
        /// <summary>
        /// Returns everything to the left of the righmost char c.
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">The search char.</param>
        /// <returns>Everything to the left of the rightmost char c, or the entire string.</returns>
        public static string LeftOfRightmostOf(string src, char c)
        {
            string ret = src;
            int idx = src.LastIndexOf(c);
            if (idx != -1)
            {
                ret = src.Substring(0, idx);
            }
            return ret;
        }
        /// <summary>
        /// Returns everything to the right of the rightmost char c.
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="c">The seach char.</param>
        /// <returns>Returns everything to the right of the rightmost search char, or an empty string.</returns>
        public static string RightOfRightmostOf(string src, char c)
        {
            string ret = String.Empty;
            int idx = src.LastIndexOf(c);
            if (idx != -1)
            {
                ret = src.Substring(idx + 1);
            }
            return ret;
        }
        /// <summary>
        /// Returns everything between the start and end chars, exclusive.
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="start">The first char to find.</param>
        /// <param name="end">The end char to find.</param>
        /// <returns>The string between the start and stop chars, or an empty string if not found.</returns>
        public static string Between(string src, char start, char end)
        {
            string ret = String.Empty;
            int idxStart = src.IndexOf(start);
            if (idxStart != -1)
            {
                ++idxStart;
                int idxEnd = src.IndexOf(end, idxStart);
                if (idxEnd != -1)
                {
                    ret = src.Substring(idxStart, idxEnd - idxStart);
                }
            }
            return ret;
        }
        /// <summary>
        /// Returns the number of occurances of "find".
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <param name="find">The search char.</param>
        /// <returns>The # of times the char occurs in the search string.</returns>
        public static int Count(string src, char find)
        {
            int ret = 0;
            foreach (char s in src)
            {
                if (s == find)
                {
                    ++ret;
                }
            }
            return ret;
        }
        /// <summary>
        /// Returns the rightmost char in src.
        /// </summary>
        /// <param name="src">The source string.</param>
        /// <returns>The rightmost char, or '\0' if the source has zero length.</returns>
        public static char Rightmost(string src)
        {
            char c = '\0';
            if (src.Length > 0)
            {
                c = src[src.Length - 1];
            }
            return c;
        }
    }

    public static class StringTool
    {
        #region StringConstantsToHelpWithComparisons
        private const string m_Letters = "abcdefghijklmnopqrstuvwxyz";
        private const string m_Digits = "0123456789";
        private const string m_ForwardSlash = "/";
        private const string m_BackSlash = "\\";
        private const string m_Period = ".";
        private const string m_DollarSign = "$";
        private const string m_PercentSign = "%";
        private const string m_Comma = ",";
        private const string m_Yes = "yes";
        private const string m_No = "no";
        private const string m_True = "true";
        private const string m_False = "false";
        private const string m_1 = "1";
        private const string m_0 = "0";
        private const string m_y = "y";
        private const string m_n = "n";
        #endregion
        #region DataTypeStringConstants
        public const string m_GUID = "guid";
        public const string m_Boolean1 = "boolean";
        public const string m_Boolean2 = "bool";
        public const string m_Byte = "byte";
        public const string m_Char = "char";
        public const string m_DateTime = "datetime";
        public const string m_DBNull = "dbnull";
        public const string m_Decimal = "decimal";
        public const string m_Double = "double";
        public const string m_Empty = "empty";
        public const string m_Int16_1 = "int16";
        public const string m_Int16_2 = "short";
        public const string m_Int32_1 = "int32";
        public const string m_Int32_2 = "int";
        public const string m_Int32_3 = "integer";
        public const string m_Int64_1 = "int64";
        public const string m_Int64_2 = "long";
        public const string m_Object = "object";
        public const string m_SByte = "sbyte";
        public const string m_Single = "single";
        public const string m_String = "string";
        public const string m_UInt16 = "uint16";
        public const string m_UInt32 = "uint32";
        public const string m_UInt64 = "uint64";
        #endregion
        #region MethodsThatCheckDataType
        /// <summary>
        /// Evaluates whether passed-in string can be converted to a bool
        /// </summary>
        /// <param name="stream">string to check</param>
        /// <returns>
        /// bool indicating whether stream is a bool (0, 1, true/True,
        /// false/False)
        /// </returns>
        public static bool IsStandardBool(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;
                stream = stream.Trim().ToLower();
                switch (stream)
                {
                    case m_0:
                        return true;
                    case m_1:
                        return true;
                    case m_True:
                        return true;
                    case m_False:
                        return true;
                    default:
                        return false;
                }
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Evaluates whether string can can be COERCED to a bool
        /// </summary>
        /// <param name="stream">string to check</param>
        /// <returns>
        /// bool indicating whether argument is a standard or custom bool
        /// (0, 1, true/True, false/False) OR (y/Y, yes/Yes, n/N, no/NO)
        /// </returns>
        public static bool IsFriendlyBool(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;
                stream = stream.Trim().ToLower();
                switch (stream)
                {
                    case m_0:
                        return true;
                    case m_1:
                        return true;
                    case m_True:
                        return true;
                    case m_False:
                        return true;
                    case m_n:
                        return true;
                    case m_y:
                        return true;
                    case m_No:
                        return true;
                    case m_Yes:
                        return true;
                    default:
                        return false;
                }
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Returns a bool conversion of the passed in string
        /// </summary>
        /// <param name="stream">string to convert/coerce</param>
        /// <returns>
        /// bool representation of passed-in string
        /// </returns>
        public static bool CoerceToBool(string stream)
        {
            try
            {
                stream = stream.Trim().ToLower();
                switch (stream)
                {
                    case m_0:
                        return true;
                    case m_1:
                        return true;
                    case m_True:
                        return true;
                    case m_False:
                        return false;
                    case m_n:
                        return false;
                    case m_y:
                        return true;
                    case m_No:
                        return false;
                    case m_Yes:
                        return true;
                    default:
                        return false;
                }
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Evaluates whether passed-in string contains any characters/
        /// digits/symbols. Trims spaces before checking.
        /// </summary>
        /// <param name="stream">string to check</param>
        /// <returns>
        /// bool indicating whether argument is void of characters/
        /// digits/symbols
        ///</returns>
        public static bool IsEmpty(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty
                    || stream.Trim() == string.Empty)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Checks each character of the string for any character other
        /// than a digit, or a dollar sign or a percentage sign. If any
        /// are found, returns false indicating that the stream is NOT
        /// a number
        /// </summary>
        /// <param name="stream">
        /// The stream of characters (string) to check
        /// </param>
        /// <returns>
        /// True/False value indicating whether the string can be
        /// coerced to a number
        /// </returns>
        public static bool IsNumber(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;

                string character = string.Empty;
                //set a string up of all characters that may indicate
                //that the stream is a number, or a formatted number:
                string validCharacters = m_Digits + m_Period +
                    m_DollarSign + m_Comma;
                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (!validCharacters.Contains(character))
                        return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Checks the string to see whether it is a number & if it is,
        /// then it checks whether there is formatting applied to that #
        /// </summary>
        /// <param name="stream">
        /// The stream of characters (string) to check
        /// </param>
        /// <returns>
        /// True/False value indicating whether the string is a number
        /// that is formatted (contains digits and number formatting)
        /// </returns>
        public static bool IsFormattedNumber(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;

                string character = string.Empty;
                //set a string up of all characters that may indicate that
                //the stream is a number, or a formatted number:
                string validCharacters = m_Digits + m_Period +
                    m_DollarSign + m_PercentSign + m_Comma;

                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (!validCharacters.Contains(character))
                        //the stream contains non-numeric characters:
                        return false;
                }
                //at this point, each single character is a number OR an
                //allowable symbol, but we must see whether those
                //characters contain a formatting character:
                string formattingCharacters = m_DollarSign +
                    m_PercentSign + m_Comma;
                for (int i = 0; i < stream.Length; i++)
                {
                    if (formattingCharacters.Contains(character))
                        return true;
                }
                //still here? then the stream is a number, but NOT a
                //formatted number
                return false;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Checks whether string can be coerced into a DateTime value
        /// </summary>
        /// <param name="stream">The string to check/// </param>
        /// <returns>
        /// bool indicating whether stream can be converted to a date
        /// </returns>
        public static bool IsDate(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;
                DateTime checkDate = new DateTime();
                bool dateType = true;
                try
                {
                    checkDate = DateTime.Parse(stream);
                }
                catch
                {
                    dateType = false;
                }
                return dateType;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Checks the string to see whether it is a number and if it is,
        /// then it checks whether there is a decimal in that number.
        /// </summary>
        /// <param name="stream">
        /// The stream of characters (string) to check
        /// </param>
        /// <returns>
        /// True/False value indicating whether the string is a
        /// double---must be a number, and include a decimal
        /// in order to pass the test
        /// </returns>
        public static bool IsDouble(string stream)
        {
            try
            {
                if (stream == null || stream == string.Empty)
                    return false;

                if (!IsNumber(stream))
                    return false;

                //at this point each character is a number OR an allowable
                //symbol; we must see whether the string holds the decimal:
                if (stream.Contains(m_Period))
                    return true;

                //still here? the stream is a #, but does NOT have a decimal
                return false;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return false;
            }
        }

        /// <summary>
        /// Checks string to see if it matches a TypeCode string and returns
        /// that TypeCode, or returns TypeCode.Empty if there is no match
        /// </summary>
        /// <param name="dataTypeString">
        /// String representation of a TypeCode (string, int, bool...)
        /// </param>
        /// <returns>TypeCode that maps to the dataTypeString</returns>
        public static TypeCode GetDataType(string dataTypeString)
        {
            try
            {
                switch (dataTypeString.ToLower())
                {
                    // todo: isn't there a better way for guid?
                    case m_GUID:
                        return TypeCode.Object;
                    case m_Boolean1:
                        return TypeCode.Boolean;
                    case m_Boolean2:
                        return TypeCode.Boolean;
                    case m_Byte:
                        return TypeCode.Byte;
                    case m_Char:
                        return TypeCode.Char;
                    case m_DateTime:
                        return TypeCode.DateTime;
                    case m_DBNull:
                        return TypeCode.DBNull;
                    case m_Decimal:
                        return TypeCode.Decimal;
                    case m_Double:
                        return TypeCode.Double;
                    case m_Empty:
                        return TypeCode.Empty;
                    case m_Int16_1:
                        return TypeCode.Int16;
                    case m_Int16_2:
                        return TypeCode.Int16;
                    case m_Int32_1:
                        return TypeCode.Int32;
                    case m_Int32_2:
                        return TypeCode.Int32;
                    case m_Int32_3:
                        return TypeCode.Int32;
                    case m_Int64_1:
                        return TypeCode.Int64;
                    case m_Int64_2:
                        return TypeCode.Int64;
                    case m_Object:
                        return TypeCode.Object;
                    case m_SByte:
                        return TypeCode.SByte;
                    case m_Single:
                        return TypeCode.Single;
                    case m_String:
                        return TypeCode.String;
                    case m_UInt16:
                        return TypeCode.UInt16;
                    case m_UInt32:
                        return TypeCode.UInt32;
                    case m_UInt64:
                        return TypeCode.UInt64;
                    default:
                        return TypeCode.Empty;
                }
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return TypeCode.Empty;
            }
        }
        #endregion
        #region StringConversions
        /// <summary>
        /// Returns a date, as coerced from the string argument. Will raise
        /// an error, if the string cannot be coerced
        /// ----so, use IsDate in this same class FIRST
        /// </summary>
        /// <param name="stream">string to get date value from</param>
        /// <returns>a DateTime object</returns>
        public static DateTime GetDate(string stream)
        {
            DateTime dateValue = new DateTime();
            try
            {
                dateValue = DateTime.Parse(stream);
                return dateValue;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return dateValue;
            }
        }

        /// <summary>
        /// Returns an int, as coerced from the string argument.
        /// Will raise an error, if the string cannot be coerced
        /// ----so, use IsNumber in this same class FIRST
        /// </summary>
        /// <param name="stream">string to get int value from</param>
        /// <returns>an int object</returns>
        public static int GetInteger(string stream)
        {
            try
            {
                int number = 0;
                if (!IsNumber(stream))
                    return number;
                //still here? check to see if it is formatted:
                if (IsFormattedNumber(stream))
                {
                    //it's formatted; replace the format characters
                    //with nothing (retain the decimal so as not to change
                    //the intended value
                    stream = stream.Replace(m_Comma, string.Empty);
                    stream = stream.Replace(m_DollarSign, string.Empty);
                    stream = stream.Replace(m_PercentSign, string.Empty);
                }
                //we've removed superfluous formatting characters, if they
                //did exist, now let's round it/convert it, and return it:
                number = Convert.ToInt32(stream);
                return number;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return 0;
            }
        }

        /// <summary>
        /// Returns a double, as coerced from the string argument.
        /// Will raise an error, if the string cannot be coerced
        /// ----so, use IsNumber in this same class FIRST
        /// </summary>
        /// <param name="stream">string to get double value from</param>
        /// <returns>a double object</returns>
        public static double GetDouble(string stream)
        {
            try
            {
                double number = 0;
                if (!IsNumber(stream))
                    return number;
                //still here? check to see if it is formatted:
                if (IsFormattedNumber(stream))
                {
                    //it's formatted; replace the format characters
                    //with nothing (retain the decimal so as not to change
                    //the intended value)
                    stream = stream.Replace(m_Comma, string.Empty);
                    stream = stream.Replace(m_DollarSign, string.Empty);
                    stream = stream.Replace(m_PercentSign, string.Empty);
                }

                //we've removed superfluous formatting characters, if they
                //did exist, now let's round it/convert it, and return it:
                number = Convert.ToDouble(stream);
                return number;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return 0;
            }
        }
        #endregion
        #region StringEdits
        /// <summary>
        /// Iterates thru an entire string, and sets the first letter of
        /// each word to uppercase, and all ensuing letters to lowercase
        /// </summary>
        /// <param name="stream">The string to alter the case of</param>
        /// <returns>
        /// Same string w/uppercase initial letters & others as lowercase
        /// </returns>
        public static string MixCase(string stream)
        {
            try
            {
                string newString = string.Empty;
                string character = string.Empty;
                string preceder = string.Empty;
                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (i > 0)
                    {
                        //look at the character immediately before current
                        preceder = stream.Substring(i - 1, 1);
                        //remove white space character from predecessor
                        if (preceder.Trim() == string.Empty)
                            //the preceding character WAS white space, so
                            //we'll change the current character to UPPER
                            character = character.ToUpper();
                        else
                            //the preceding character was NOT white space,
                            //we'll force the current character to LOWER
                            character = character.ToLower();
                    }
                    else
                        //index is 0, thus we are at the first character
                        character = character.ToUpper();
                    //add the altered character to the new string:
                    newString += character;
                }
                return newString;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Iterates thru a string, and removes anything set to clean.
        /// Except---Does NOT remove anything in exceptionsToAllow
        /// </summary>
        /// <param name="stream">
        /// The string to clean</param>
        /// <returns>
        /// The same string, missing all elements that were set to clean
        /// (except when a character was listed in exceptionsToAllow)
        /// </returns>
        public static string Clean(string stream, bool cleanWhiteSpace,
            bool cleanDigits, bool cleanLetters, string exceptionsToAllow)
        {
            try
            {
                string newString = string.Empty;
                string character = string.Empty;
                string blessed = string.Empty;
                if (!cleanDigits)
                    blessed += m_Digits;
                if (!cleanLetters)
                    blessed += m_Letters;
                blessed += exceptionsToAllow;
                //we set the comparison string to lower
                //and will compare each character's lower case version
                //against the comparison string, without
                //altering the original case of the character
                blessed = blessed.ToLower();
                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (blessed.Contains(character.ToLower()))
                        //add the altered character to the new string:
                        newString += character;
                    else if (character.Trim() == string.Empty &&
                        !cleanWhiteSpace)
                        newString += character;
                }
                return newString;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }
        #endregion
        #region StringLocators
        /// <summary>
        /// Parses a file system or url path, and locates the file name
        /// </summary>
        /// <param name="fullPath">
        /// String indicating a file system or url path to a file
        /// </param>
        /// <param name="includeFileExtension">
        /// Whether to return file extension in addition to file name
        /// </param>
        /// <returns>
        /// File name, if found, and extension if requested, and located
        /// </returns>
        public static string GetFileNameFromPath(string fullPath,
            bool includeFileExtension)
        {
            try
            {
                bool url = fullPath.Contains(m_ForwardSlash);
                string search = string.Empty;
                if (url)
                    search = m_ForwardSlash;
                else
                    search = m_BackSlash;
                string portion = string.Empty;

                int decimals = GetKeyCharCount(fullPath, m_Period);
                if (decimals >= 1)
                    //get all text to the RIGHT of the LAST slash:
                    portion = GetExactPartOfString(fullPath, search, false,
                        false, false);
                else
                    return string.Empty;

                if (includeFileExtension)
                    return portion;
                search = m_Period;
                portion = GetExactPartOfString(portion, search, false,
                    true, false);
                return portion;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Parses a url or file stream string, to get and return the
        /// path portion (sans the file name and extension)
        /// </summary>
        /// <param name="fullPath">
        /// A string indicating a file system path or a url. Can
        /// contain a file name/extension.
        /// </param>
        /// <returns>
        /// The original path minus the file name and extension,
        /// if it had existed, with no extension will return
        /// the original string, plus an optional slash
        /// </returns>
        public static string GetFolderPath(string fullPath)
        {
            try
            {
                bool url = fullPath.Contains(m_ForwardSlash);
                string slash = string.Empty;
                if (url)
                    slash = m_ForwardSlash;
                else
                    slash = m_BackSlash;

                string fileName = GetFileNameFromPath(fullPath, true);
                //use tool to return all text to the LEFT of the file name
                string portion = GetStringBetween(fullPath, string.Empty,
                    fileName);

                //add the pertinent slash to the end of the string;
                if (portion.Length > 0 && portion.Substring(
                    portion.Length - 1, 1) != slash)
                    portion += slash;
                return portion;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Useful to pinpoint exact string between whatever
        /// characters/string you wish to grab text from
        /// </summary>
        /// <param name="stream">
        /// string from which to cull subtext from
        /// </param>
        /// <param name="from">
        /// string that precedes the text you are looking for
        /// </param>
        /// <param name="to">
        /// string that follows the text you are looking for
        /// </param>
        /// <returns>
        /// The string between point x and point y
        /// </returns>
        public static string GetStringBetween(string stream, string from,
            string to)
        {
            try
            {
                string subField = string.Empty;
                subField = RightOf(stream, from);
                subField = LeftOf(subField, to);
                return subField;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Will return the text to the LEFT of indicated substring
        /// </summary>
        /// <param name="stream">
        /// string from which to cull a portion of text
        /// </param>
        /// <param name="stringToStopAt">
        /// string that indicates what char or string to stop at
        /// </param>
        /// <returns>
        /// The string to the left of point x (stringToStopAt)
        /// </returns>
        public static string LeftOf(string stream, string stringToStopAt)
        {
            try
            {
                if (stringToStopAt == null || stringToStopAt == string.Empty)
                    return stream;

                int stringLength = stream.Length;
                int findLength = stringToStopAt.Length;

                stringToStopAt = stringToStopAt.ToLower();
                string temp = stream.ToLower();
                int i = temp.IndexOf(stringToStopAt);

                if ((i <= -1) && (stringToStopAt != temp.Substring(0, findLength))
                    || (i == -1))
                    return stream;

                string result = stream.Substring(0, i);
                return result;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Will return the text to the RIGHT of whatever substring you indicate
        /// </summary>
        /// <param name="stream">
        /// string from which to cull a portion of text
        /// </param>
        /// <param name="stringToStartAfter">
        /// string that indicates what char or string to start after
        /// </param>
        /// <returns>
        /// The string to the right of point x (stringToStartAfter)
        /// </returns>
        public static string RightOf(string stream, string stringToStartAfter)
        {
            try
            {
                if (stringToStartAfter == null || stringToStartAfter == string.Empty)
                    return stream;
                stringToStartAfter = stringToStartAfter.ToLower();
                string temp = stream.ToLower();
                int findLength = stringToStartAfter.Length;
                int i = temp.IndexOf(stringToStartAfter);
                if ((i <= -1) && (stringToStartAfter != temp.Substring(0, findLength))
                    || (i == -1))
                    return stream;

                string result =
                    stream.Substring(i + findLength, stream.Length - (i + findLength));
                return result;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Searches a string for every single instance of the passed-in
        /// field delimiters, and returns all the values between those
        /// delimiters, as a List object
        /// </summary>
        /// <param name="streamToSearch">string to search</param>
        /// <param name="leftFieldDelimiter">string to start at</param>
        /// <param name="rightFieldDelimiter">string to stop at</param>
        /// <returns>A List object of strings</returns>
        public static List<string> GetEachFieldValue(string streamToSearch,
            string leftFieldDelimiter, string rightFieldDelimiter)
        {
            string search = streamToSearch;
            string field = string.Empty;
            List<string> fields = new List<string>();
            while (!string.IsNullOrEmpty(search)
                && search.Contains(leftFieldDelimiter)
                && search.Contains(rightFieldDelimiter))
            {
                //get the val and add to list
                field = GetStringBetween(search, leftFieldDelimiter,
                    rightFieldDelimiter);
                if (!string.IsNullOrEmpty(field))
                    fields.Add(field);
                //shorten the search string and continue
                search = RightOf(search, field + rightFieldDelimiter);
            }
            return fields;
        }

        /// <summary>
        /// Instructions on using arguments:
        /// Set firstInstance = true, to stop at first instance of locateChar
        /// If firstInstance = false, then the LAST instance of locateChar will be used
        /// Set fromLeft = true, to return string from the left of locateChar
        /// If fromLeft = false, then the string from the right of locateChar
        /// will be returned.
        /// Set caseSensitive to true/false for case-sensitivity
        /// EXAMPLES:
        /// GetPartOfString('aunt jemima', 'm', 'true', 'true')
        /// will return 'aunt je'
        /// GetPartOfString('aunt jemima', 'm', 'true', 'false')
        /// </summary>
        /// <param name="stream">
        /// The string from which to cull a portion of text
        /// </param>
        /// <param name="locateChar">
        /// The character or string that is the marker
        /// for which to grab text (from left or right depending
        /// on other argument)
        /// </param>
        /// <param name="firstInstance">
        /// Whether or not to get the substring from the first
        /// encountered instance of the locateChar argument
        /// </param>
        /// <param name="fromLeft">
        /// Whether to search from the left. If set to false,
        /// then the string will be searched from the right.
        /// </param>
        /// <param name="caseSensitive">
        /// Whether to consider case (upper/lower)
        /// </param>
        /// <returns>
        /// A portion of the input string, based on ensuing arguments
        /// </returns>
        public static string GetExactPartOfString(string stream, string locateChar,
                  bool firstInstance, bool fromLeft, bool caseSensitive)
        {
            try
            {
                stream = stream.ToString();
                string tempStream = string.Empty;
                string tempLocateChar = string.Empty;
                if (!caseSensitive)
                { //case doesn't matter, convert to lower:
                    tempStream = stream.ToLower();
                    tempLocateChar = locateChar.ToLower();
                }
                //default charCnt to 1; for first inst of locateChar:
                int charCount = 1;
                if (firstInstance == false)
                    //get number of times char exists in string:
                    if (caseSensitive)
                        charCount = GetKeyCharCount(stream, locateChar);
                    else
                        charCount = GetKeyCharCount(tempStream, tempLocateChar);
                //get position of first/last inst of char in str:
                int position = 0;
                if (caseSensitive)
                    position = GetCharPosition(stream, locateChar, charCount);
                else
                    position = GetCharPosition(tempStream, tempLocateChar, charCount);
                string result = string.Empty;
                //chk that character exists in str:
                if (position == -1)
                    result = string.Empty;
                else
                {
                    //char exists, proceed:
                    int streamLength = stream.Length;
                    if (fromLeft == true)
                        //return string from left:
                        result = stream.Substring(0, position);
                    else
                    {
                        //return string from right:
                        position += 1;
                        result = stream.Substring(position, streamLength - position);
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Returns the number of times, that the key character is found
        /// in the stream string
        /// </summary>
        /// <param name="stream">
        /// string in which to locate key character
        /// </param>
        /// <param name="keyChar">
        /// key character: the string or char to count inside the stream
        /// </param>
        /// <returns>
        /// The number of times the string or char was located
        /// </returns>
        public static int GetKeyCharCount(string stream, string keyChar)
        {
            try
            {
                string current;
                int keyCount = 0;
                for (int i = 0; i < stream.Length; i++)
                {
                    current = stream.Substring(i, 1);
                    if (current == keyChar)
                        keyCount += 1;
                }
                if (keyCount <= 0)
                    return -1;
                else
                    return keyCount;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return -1;
            }
        }

        /// <summary>
        /// Is CASE-SENSITIVE
        /// Returns x position of sChar in sstream, where x = iCharInst.
        /// If: getCharPos('pineapple', 'p', 3) Then: 6 is returned
        /// </summary>
        /// <param name="stream">
        /// string in which to pinpoint the character (or string) position
        /// </param>
        /// <param name="charToPinpoint">character or string to locate</param>
        /// <param name="whichCharInstance">
        /// Number indicating WHICH instance of the character/string to locate
        /// </param>
        /// <returns>
        /// The index of the character or string found inside the input string.
        /// Will return -1 if the string/character is not found, or if the
        /// instance number is not found
        /// </returns>
        public static int GetCharPosition(string stream, string charToPinpoint, int whichCharInstance)
        {
            try
            {
                string current;
                int keyCharCount = 0;
                for (int i = 0; i < stream.Length; i++)
                {
                    current = stream.Substring(i, 1);
                    //was BLOCKED SCRIPT sCurr = sstream.charAt(i);
                    if (current == charToPinpoint)
                    {
                        keyCharCount += 1;
                        if (keyCharCount == whichCharInstance)
                            return i;
                    }
                }
                return -1;
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
                //ErrorTool.ProcessError(ex);
                return -1;
            }
        }
        #endregion
    }

    public static class StringUtils
    {
        public const string CarriageReturnLineFeed = "\r\n";
        public const string Empty = "";
        public const char CarriageReturn = '\r';
        public const char LineFeed = '\n';
        public const char Tab = '\t';

        /// <summary>
        /// Determines whether the string contains white space.
        /// </summary>
        /// <param name="s">The string to test for white space.</param>
        /// <returns>
        /// 	<c>true</c> if the string contains white space; otherwise, <c>false</c>.
        /// </returns>
        public static bool ContainsWhiteSpace(string s)
        {
            if (s == null)
                throw new ArgumentNullException("s");

            for (int i = 0; i < s.Length; i++)
            {
                if (char.IsWhiteSpace(s[i]))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Determines whether the string is all white space. Empty string will return false.
        /// </summary>
        /// <param name="s">The string to test whether it is all white space.</param>
        /// <returns>
        /// 	<c>true</c> if the string is all white space; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsWhiteSpace(string s)
        {
            if (s == null)
                throw new ArgumentNullException("s");

            if (s.Length == 0)
                return false;

            for (int i = 0; i < s.Length; i++)
            {
                if (!char.IsWhiteSpace(s[i]))
                    return false;
            }

            return true;
        }

        /// <summary>
        /// Ensures the target string ends with the specified string.
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="value">The value.</param>
        /// <returns>The target string with the value string at the end.</returns>
        public static string EnsureEndsWith(string target, string value)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            if (value == null)
                throw new ArgumentNullException("value");

            if (target.Length >= value.Length)
            {
                if (string.Compare(target, target.Length - value.Length, value, 0, value.Length, StringComparison.OrdinalIgnoreCase) ==
                                0)
                    return target;

                string trimmedString = target.TrimEnd(null);

                if (string.Compare(trimmedString, trimmedString.Length - value.Length, value, 0, value.Length,
                                StringComparison.OrdinalIgnoreCase) == 0)
                    return target;
            }

            return target + value;
        }

        /// <summary>
        /// Determines whether the SqlString is null or empty.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns>
        /// 	<c>true</c> if the SqlString is null or empty; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullOrEmpty(SqlString s)
        {
            if (s.IsNull)
                return true;
            else
                return string.IsNullOrEmpty(s.Value);
        }

        /// <summary>
        /// Determines whether the given string is null or empty or whitespace.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns>
        /// 	<c>true</c> if the given string is null or empty or whitespace; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullOrEmptyOrWhiteSpace(string s)
        {
            if (string.IsNullOrEmpty(s))
                return true;
            else if (IsWhiteSpace(s))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Indents the specified string.
        /// </summary>
        /// <param name="s">The string to indent.</param>
        /// <param name="indentation">The number of characters to indent by.</param>
        /// <returns></returns>
        public static string Indent(string s, int indentation)
        {
            return Indent(s, indentation, ' ');
        }

        /// <summary>
        /// Indents the specified string.
        /// </summary>
        /// <param name="s">The string to indent.</param>
        /// <param name="indentation">The number of characters to indent by.</param>
        /// <param name="indentChar">The indent character.</param>
        /// <returns></returns>
        public static string Indent(string s, int indentation, char indentChar)
        {
            if (s == null)
                throw new ArgumentNullException("s");

            if (indentation <= 0)
                throw new ArgumentException("Must be greater than zero.", "indentation");

            StringReader sr = new StringReader(s);
            StringWriter sw = new StringWriter();

            ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line)
            {
                tw.Write(new string(indentChar, indentation));
                tw.Write(line);
            });

            return sw.ToString();
        }

        private delegate void ActionLine(TextWriter textWriter, string line);

        private static void ActionTextReaderLine(TextReader textReader, TextWriter textWriter, ActionLine lineAction)
        {
            string line;
            bool firstLine = true;
            while ((line = textReader.ReadLine()) != null)
            {
                if (!firstLine)
                    textWriter.WriteLine();
                else
                    firstLine = false;

                lineAction(textWriter, line);
            }
        }

        /// <summary>
        /// Numbers the lines.
        /// </summary>
        /// <param name="s">The string to number.</param>
        /// <returns></returns>
        public static string NumberLines(string s)
        {
            if (s == null)
                throw new ArgumentNullException("s");

            StringReader sr = new StringReader(s);
            StringWriter sw = new StringWriter();

            int lineNumber = 1;

            ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line)
            {
                tw.Write(lineNumber.ToString().PadLeft(4));
                tw.Write(". ");
                tw.Write(line);

                lineNumber++;
            });

            return sw.ToString();
        }

        /// <summary>
        /// Nulls an empty string.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns>Null if the string was null, otherwise the string unchanged.</returns>
        public static string NullEmptyString(string s)
        {
            return (string.IsNullOrEmpty(s)) ? null : s;
        }

        /// <summary>
        /// Replaces the new lines in a string with the given replacement characters.
        /// </summary>
        /// <param name="s">The string to replace new lines in.</param>
        /// <param name="replacement">The replacement characters.</param>
        /// <returns></returns>
        public static string ReplaceNewLines(string s, string replacement)
        {
            StringReader sr = new StringReader(s);
            StringBuilder sb = new StringBuilder();

            bool first = true;

            string line;
            while ((line = sr.ReadLine()) != null)
            {
                if (first)
                    first = false;
                else
                    sb.Append(replacement);

                sb.Append(line);
            }

            return sb.ToString();
        }

        public static string RemoveHtml(string s)
        {
            return RemoveHtmlInternal(s, null);
        }

        public static string RemoveHtml(string s, IList<string> removeTags)
        {
            if (removeTags == null)
                throw new ArgumentNullException("removeTags");

            return RemoveHtmlInternal(s, removeTags);
        }

        private static string RemoveHtmlInternal(string s, IList<string> removeTags)
        {
            List<string> removeTagsUpper = null;

            if (removeTags != null)
            {
                removeTagsUpper = new List<string>(removeTags.Count);

                foreach (string tag in removeTags)
                {
                    removeTagsUpper.Add(tag.ToUpperInvariant());
                }
            }

            Regex anyTag = new Regex(@"<[/]{0,1}\s*(?<tag>\w*)\s*(?<attr>.*?=['""].*?[""'])*?\s*[/]{0,1}>", RegexOptions.Compiled);

            return anyTag.Replace(s, delegate(Match match)
            {
                string tag = match.Groups["tag"].Value.ToUpperInvariant();

                if (removeTagsUpper == null)
                    return string.Empty;
                else if (removeTagsUpper.Contains(tag))
                    return string.Empty;
                else
                    return match.Value;
            });
        }

        /// <summary>
        /// Truncates the specified string.
        /// </summary>
        /// <param name="s">The string to truncate.</param>
        /// <param name="maximumLength">The maximum length of the string before it is truncated.</param>
        /// <returns></returns>
        public static string Truncate(string s, int maximumLength)
        {
            return Truncate(s, maximumLength, "...");
        }

        /// <summary>
        /// Truncates the specified string.
        /// </summary>
        /// <param name="s">The string to truncate.</param>
        /// <param name="maximumLength">The maximum length of the string before it is truncated.</param>
        /// <param name="suffix">The suffix to place at the end of the truncated string.</param>
        /// <returns></returns>
        public static string Truncate(string s, int maximumLength, string suffix)
        {
            if (suffix == null)
                throw new ArgumentNullException("suffix");

            if (maximumLength <= 0)
                throw new ArgumentException("Maximum length must be greater than zero.", "maximumLength");

            int subStringLength = maximumLength - suffix.Length;

            if (subStringLength <= 0)
                throw new ArgumentException("Length of suffix string is greater or equal to maximumLength");

            if (s != null && s.Length > maximumLength)
            {
                string truncatedString = s.Substring(0, subStringLength);
                // incase the last character is a space
                truncatedString = truncatedString.TrimEnd();
                truncatedString += suffix;

                return truncatedString;
            }
            else
            {
                return s;
            }
        }

        /// <summary>
        /// Creates a StringWriter with the specified capacity.
        /// </summary>
        /// <param name="capacity">The capacity of the StringWriter.</param>
        /// <returns></returns>
        public static StringWriter CreateStringWriter(int capacity)
        {
            StringBuilder sb = new StringBuilder(capacity);
            StringWriter sw = new StringWriter(sb);

            return sw;
        }

        /// <summary>
        /// Gets the length of a string, returning null if the string is null.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static int? GetLength(string value)
        {
            if (value == null)
                return null;
            else
                return value.Length;
        }
    }
}
